package com.polidea.rxohosble2.sample.example2_connection;

import com.polidea.rxohosble2.RxBleConnection;
import com.polidea.rxohosble2.RxBleDevice;
import com.polidea.rxohosble2.internal.RxBleLog;
import com.polidea.rxohosble2.sample.ResourceTable;
import com.polidea.rxohosble2.sample.SampleApplication;
import com.polidea.rxohosble2.sample.DeviceAbility;
import com.polidea.rxohosble2.sample.util.Utils;
import io.reactivex.ohos.schedulers.OhosSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.bluetooth.ble.BlePeripheralDevice;

public class ConnectionExampleAbility extends Ability {

    Text connectionStateView;
    Button connectButton;
    TextField textMtu;
    Button setMtuButton;
    Switch autoConnectToggleSwitch;
    private RxBleDevice bleDevice;
    private Disposable connectionDisposable;
    private final CompositeDisposable mtuDisposable = new CompositeDisposable();
    private Disposable stateDisposable;

    public void onConnectToggleClick(Component component) {
        if (isConnected()) {
            triggerDisconnect();
        } else {
            connectionDisposable = bleDevice.establishConnection(autoConnectToggleSwitch.isChecked())
                    .observeOn(OhosSchedulers.mainThread())
                    .doFinally(this::dispose)
                    .subscribe(this::onConnectionReceived, this::onConnectionFailure);
        }
    }

    public void onSetMtu(Component component) {
        final Disposable disposable = bleDevice.establishConnection(false)
                .flatMapSingle(rxBleConnection -> {
                    RxBleLog.i("Ability -- establishConnection result:"+rxBleConnection);
                    return rxBleConnection.requestMtu(72);
                })
                .take(1) // Disconnect automatically after discovery
                .observeOn(OhosSchedulers.mainThread())
                .doFinally(this::updateUI)
                .subscribe(this::onMtuReceived, this::onConnectionFailure);
        mtuDisposable.add(disposable);
    }

    BlePeripheralDevice peripheralDevice = null;

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        setPattern(ResourceTable.Pattern_base);
        super.setUIContent(ResourceTable.Layout_ability_example2);
        connectionStateView = (Text)findComponentById(ResourceTable.Id_connection_state);
        connectButton = (Button) findComponentById(ResourceTable.Id_connect_toggle);
        textMtu = (TextField) findComponentById(ResourceTable.Id_newMtu);
        setMtuButton = (Button)findComponentById(ResourceTable.Id_set_mtu);
        autoConnectToggleSwitch = (Switch)findComponentById(ResourceTable.Id_autoconnect);

        String macAddress = intent.getStringParam(DeviceAbility.EXTRA_MAC_ADDRESS);
        ((Text) findComponentById(ResourceTable.Id_title)).setText(getString(ResourceTable.String_mac_address, macAddress));

        peripheralDevice = BlePeripheralDevice.createInstance(macAddress);

        connectButton.setClickedListener(this::onConnectToggleClick);
        setMtuButton.setClickedListener(this::onSetMtu);

        bleDevice = SampleApplication.getRxBleClient(this).getBleDevice(macAddress);
        // How to listen for connection state changes
        // Note: it is meant for UI updates only — one should not observeConnectionStateChanges() with BLE connection logic
        stateDisposable = bleDevice.observeConnectionStateChanges()
                .observeOn(OhosSchedulers.mainThread())
                .subscribe(this::onConnectionStateChange);
    }

    public boolean isConnected() {
        return bleDevice.getConnectionState() == RxBleConnection.RxBleConnectionState.CONNECTED;
    }

    private void onConnectionFailure(Throwable throwable) {
        //noinspection ConstantConditions
        Utils.showToast(this, "Connection error: "+ throwable);
    }

    @SuppressWarnings("unused")
    private void onConnectionReceived(RxBleConnection connection) {
        //noinspection ConstantConditions
        Utils.showToast(this, "Connection received ");
    }

    private void onConnectionStateChange(RxBleConnection.RxBleConnectionState newState) {
        connectionStateView.setText(newState.toString());
        updateUI();
    }

    public boolean isMtuFlage() {
        return flageMtu;
    }

    public boolean flageMtu=false;

    public void onMtuReceived(Integer mtu) {
        //noinspection ConstantConditions
        flageMtu=true;
        Utils.showToast(this, "MTU received: "+ mtu);
    }

    private void dispose() {
        connectionDisposable = null;
        updateUI();
    }

    private void triggerDisconnect() {

        if (connectionDisposable != null) {
            connectionDisposable.dispose();
        }
    }

    public void updateUI() {
        final boolean connected = isConnected();
        connectButton.setText(connected ? ResourceTable.String_disconnect : ResourceTable.String_connect);
        autoConnectToggleSwitch.setEnabled(!connected);
    }

    @Override
    protected void onInactive() {
        super.onInactive();

        triggerDisconnect();
        mtuDisposable.clear();
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (stateDisposable != null) {
            stateDisposable.dispose();
        }
    }
}
